package cn.changeforyou.web.dao.mybatis.ext.extBuilder.builder;

import cn.changeforyou.web.dao.mybatis.ext.dao.BaseDao;
import cn.changeforyou.web.dao.mybatis.ext.extBuilder.DaoSpringHolder;
import cn.changeforyou.web.dao.mybatis.ext.extBuilder.SqlContext;
import cn.changeforyou.web.dao.mybatis.ext.extBuilder.TableInfoForm;
import cn.changeforyou.web.dao.mybatis.ext.extBuilder.writer.*;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.*;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.condition.CombineAnnotationEnum;
import cn.changeforyou.web.utils.tree.Tree;
import cn.changeforyou.web.utils.tree.TreeNode;
import cn.changeforyou.web.utils.tree.TreeUtil;
import org.apache.ibatis.mapping.SqlCommandType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * select语句构建器
 *
 * @author zhyu
 * @version 1.0
 * @date 2022/2/10 16:36
 */
public class SelectBuilder {

    public static final String META_INFO = "meta_info";

    private static SelectSimpleSqlWriter selectSimpleSqlWriter;
    private static FromSimpleSqlWriter fromSimpleSqlWriter;
    private static WhereEmptyAndIdSqlWriter whereEmptyAndIdSqlWriter;
    private static WhereEntitySqlWriter whereEntitySqlWriter;
    private static WhereConditionSqlWriter whereConditionSqlWriter;

    static {
        selectSimpleSqlWriter = DaoSpringHolder.getBean(SelectSimpleSqlWriter.class);
        fromSimpleSqlWriter = DaoSpringHolder.getBean(FromSimpleSqlWriter.class);
        whereEmptyAndIdSqlWriter = DaoSpringHolder.getBean(WhereEmptyAndIdSqlWriter.class);
        whereEntitySqlWriter = DaoSpringHolder.getBean(WhereEntitySqlWriter.class);
        whereConditionSqlWriter = DaoSpringHolder.getBean(WhereConditionSqlWriter.class);
    }

    /**
     * 构建
     *
     * @param mappedStatementMetaInfo
     * @return
     */
    public static void buildAndSet(MappedStatementMetaInfo mappedStatementMetaInfo) {
        SqlContext sqlContext = prepareBuild(mappedStatementMetaInfo);

        //构建sql
        //构建select
        selectSimpleSqlWriter.writeSql(sqlContext);

        fromSimpleSqlWriter.writeSql(sqlContext);

        //构建where
        MappedStatementParameterType mappedStatementParameterType = sqlContext.getMappedStatementParameterType();
        switch (mappedStatementParameterType) {
            case selectEmpty:
            case selectById:
                whereEmptyAndIdSqlWriter.writeSql(sqlContext);
                break;
            case selectByEntity:
                whereEntitySqlWriter.writeSql(sqlContext);
                break;
            case selectByCondition:
                whereConditionSqlWriter.writeSql(sqlContext);
                break;

        }

        String sql = afterBuilder(sqlContext);
        mappedStatementMetaInfo.setSql(sql);

        //构建Result
        if (sqlContext.getSqlCommandType() == SqlCommandType.SELECT) {
            if (MappedStatementResultType.selectVOs == sqlContext.getMappedStatementResultType() ||
                    MappedStatementResultType.selectVO == sqlContext.getMappedStatementResultType()) {
                mappedStatementMetaInfo.setResultType(sqlContext.getReturnType());
            }
        }
    }

    /**
     * build后方法
     *
     * @param context
     * @return
     */
    private static String afterBuilder(SqlContext context) {
        if (context.isScriptModel()) {
            return "<script>" + context.getSql().toString() + "</script>";
        }
        return context.getSql().toString();
    }

    /**
     * 构建准备工作
     *
     * @param mappedStatementMetaInfo
     * @return
     */
    private static SqlContext prepareBuild(MappedStatementMetaInfo mappedStatementMetaInfo) {
        SqlContext sqlContext = new SqlContext();
        sqlContext.setReturnType(mappedStatementMetaInfo.getMappedStatementBaseInfo().getReturnType());
        EntityMetaInfo entityMetaInfo = mappedStatementMetaInfo.getEntityMetaInfo();
        sqlContext.setWhereJavaParamPrefix(BaseDao.CONDITION_PARAM);

        //处理主键
        for (FieldMetaInfo fieldMetaInfo : entityMetaInfo.getFieldMetaInfoList()) {
            if (fieldMetaInfo.isId()) {
                sqlContext.setPrimaryKeyInfo(fieldMetaInfo);
                break;
            }
        }

        //处理类型
        sqlContext.setSqlCommandType(mappedStatementMetaInfo.getSqlCommandType());
        MappedStatementResultType mappedStatementResultType = mappedStatementMetaInfo.getMappedStatementBaseInfo().getMappedStatementResultType();
        sqlContext.setMappedStatementResultType(mappedStatementResultType);
        MappedStatementParameterType mappedStatementParameterType = mappedStatementMetaInfo.getMappedStatementBaseInfo().getMappedStatementParameterType();
        sqlContext.setMappedStatementParameterType(mappedStatementParameterType);

        //处理select的columns
        if (mappedStatementResultType == MappedStatementResultType.selectVO || mappedStatementResultType == MappedStatementResultType.selectVOs) {
            sqlContext.setSelectMetaInfo(mappedStatementMetaInfo.getVoMetaInfo().getFieldMetaInfoList());
            sqlContext.setReturnType(mappedStatementMetaInfo.getVoMetaInfo().getEntityClass());
        } else if (mappedStatementResultType == MappedStatementResultType.count) {
            //啥事儿都不做
        } else {
            sqlContext.setSelectMetaInfo(entityMetaInfo.getFieldMetaInfoList());
        }

        //处理select的From
        TableInfoForm tableInfoForm = new TableInfoForm();
        tableInfoForm.setTableName(entityMetaInfo.getTableName());
        tableInfoForm.setTableAlias(entityMetaInfo.getTableNameAlias());
        sqlContext.setMainTableForm(tableInfoForm);



        //解析参数的树
        if (MappedStatementParameterType.selectByEntity == mappedStatementParameterType) {
           WhereBuildUtil.buildWhereTreeByFieldMetaInfoList(mappedStatementMetaInfo.getEntityMetaInfo().getFieldMetaInfoList(), sqlContext);
        } else if (MappedStatementParameterType.selectByCondition == mappedStatementParameterType) {
            WhereBuildUtil.buildWhereTreeByConditionMetaInfo(mappedStatementMetaInfo.getConditionMetaInfo(), sqlContext);
        }
        return sqlContext;
    }
}
